use crate::alloc_::_mi_segment_page_of;
use crate::init::*;
use crate::page_queue::_mi_bin;
use crate::segment::_mi_segment_page_start;
use crate::types::{mi_block_t, mi_page_queue_t, mi_page_t, mi_segment_t};
use crate::types_extra::MI_SEGMENT_MASK;
use crate::{
    types::{mi_heap_t, mi_page_s},
    types_extra::MI_SMALL_SIZE_MAX,
};

pub fn _mi_thread_id() -> usize {
    unsafe { libc::gettid() as usize }
}

pub unsafe fn _mi_heap_get_free_small_page(heap: *mut mi_heap_t, size: usize) -> *mut mi_page_s {
    debug_assert!(size <= MI_SMALL_SIZE_MAX);
    let heap = &mut *heap;
    heap.pages_free_direct[_mi_wsize_from_size(size)]
}

pub unsafe fn _mi_wsize_from_size(size: usize) -> usize {
    (size + size_of::<*mut ()>() - 1) / size_of::<*mut ()>()
}

pub unsafe fn mi_heap_is_initialized(heap: *mut mi_heap_t) -> bool {
    debug_assert!(!heap.is_null());
    heap as *const _ != &_mi_heap_empty as _
}

pub unsafe fn mi_page_queue(heap: *mut mi_heap_t, size: usize) -> *mut mi_page_queue_t {
    &mut (&mut *heap).pages[_mi_bin(size) as usize]
}

pub unsafe fn _mi_ptr_segment(p: *mut u8) -> *mut mi_segment_t {
    ((p as usize) & !MI_SEGMENT_MASK) as _
}

pub unsafe fn _mi_page_segment(page: *mut mi_page_t) -> *mut mi_segment_t {
    _mi_ptr_segment(page as _)
}

pub unsafe fn _mi_page_start(
    segment: *mut mi_segment_t,
    page: *mut mi_page_t,
    page_size: Option<&mut usize>,
) -> *mut u8 {
    _mi_segment_page_start(segment, page, page_size)
}

pub unsafe fn mi_block_nextx(_cookie: usize, block: *mut mi_block_t) -> *mut mi_block_t {
    // TODO! MI_SECURE
    (&mut *block).next as *mut mi_block_t
}

pub unsafe fn mi_block_set_nextx(_cookie: usize, block: *mut mi_block_t, next: *mut mi_block_t) {
    // TODO! MI_SECURE
    (&mut *block).next = next as _;
}

pub unsafe fn mi_block_next(page: *mut mi_page_t, block: *mut mi_block_t) -> *mut mi_block_t {
    mi_block_nextx((&mut *page).cookie, block)
}

pub unsafe fn mi_block_set_next(
    page: *mut mi_page_t,
    block: *mut mi_block_t,
    next: *mut mi_block_t,
) {
    mi_block_set_nextx((&mut *page).cookie, block, next)
}

pub unsafe fn mi_page_mostly_used(page: *mut mi_page_t) -> bool {
    if page.is_null() {
        return true;
    }

    let frac = (&*page).reserved / 8;
    (&*page).reserved as usize - (&*page).used + (&*page).thread_freed < frac as usize
}

pub unsafe fn mi_page_immediate_available(page: *mut mi_page_t) -> bool {
    !(&mut *page).free.is_null()
}

pub unsafe fn _mi_ptr_page(p: *mut u8) -> *mut mi_page_t {
    _mi_segment_page_of(_mi_ptr_segment(p), p)
}
